using System;
using System.Data.Common;
using System.Runtime.Serialization;
using OracleInternal.Common;
using OracleInternal.Network;

namespace Oracle.ManagedDataAccess.Client
{
	[Serializable]
	public sealed class OracleException : DbException
	{
		private OracleErrorCollection m_errors;

		internal OracleLogicalTransaction m_OracleLogicalTransaction;

		public OracleLogicalTransaction OracleLogicalTransaction => m_OracleLogicalTransaction;

		public OracleErrorCollection Errors => m_errors;

		public string DataSource => m_errors[0].DataSource;

		public override string Message
		{
			get
			{
				string text = string.Empty;
				if (m_errors != null)
				{
					int count = m_errors.Count;
					int num = 0;
					while (num < count)
					{
						text += m_errors[num].Message;
						if (++num < count)
						{
							text += "\n";
						}
					}
				}
				return text.TrimEnd('\n');
			}
		}

		public string Procedure => m_errors[0].Procedure;

		public override string Source => m_errors[0].Source;

		public int Number => m_errors[0].Number;

		public bool IsRecoverable => m_errors[0].IsRecoverable;

		internal OracleException(OracleErrorCollection oec)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
			m_errors = oec;
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
		}

		internal OracleException(NetworkException inner)
			: base(inner.Message, inner)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
			m_errors = new OracleErrorCollection();
			m_errors.Add(new OracleError(inner.ErrorCode, inner.Source, string.Empty, inner.Message));
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
		}

		internal OracleException(int errCode, string dataSrc, string procedure, string errMsg, int parseErrorOffset = -1)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
			m_errors = new OracleErrorCollection();
			m_errors.Add(new OracleError(errCode, parseErrorOffset, dataSrc, procedure, errMsg));
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
		}

		internal OracleException(int errCode, string dataSrc, string procedure, string errMsg, Exception innerException)
			: base(innerException.Message, innerException)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
			m_errors = new OracleErrorCollection();
			m_errors.Add(new OracleError(errCode, dataSrc, procedure, errMsg));
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
		}

		private OracleException(SerializationInfo info, StreamingContext context)
			: base(info, context)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
			m_errors = (OracleErrorCollection)info.GetValue(GetType().FullName, typeof(OracleErrorCollection));
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleException, OracleTraceFuncName.ctor);
			}
		}

		public override void GetObjectData(SerializationInfo info, StreamingContext context)
		{
			if (ProviderConfig.m_bTraceLevelPublic)
			{
				Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleException, OracleTraceFuncName.GetObjectData);
			}
			try
			{
				base.GetObjectData(info, context);
				info.AddValue(GetType().FullName, m_errors);
			}
			catch (Exception ex)
			{
				HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleException, OracleTraceFuncName.GetObjectData, ex);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPublic)
				{
					Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleException, OracleTraceFuncName.GetObjectData);
				}
			}
		}

		internal void AddBindErrorToCollection(int errCode, string dataSrc, string procedure, string errMsg, int arrayBindIndex)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, OracleTraceClassName.OracleException, OracleTraceFuncName.AddBindErrorToCollection);
			}
			m_errors.Add(new OracleError(errCode, dataSrc, procedure, errMsg, arrayBindIndex));
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, OracleTraceClassName.OracleException, OracleTraceFuncName.AddBindErrorToCollection);
			}
		}

		internal static void HandleError(OracleTraceLevel level, OracleTraceTag tag, OracleTraceClassName className, OracleTraceFuncName funcName, Exception ex, OracleLogicalTransaction oracleLogicalTransaction = null)
		{
			bool flag = false;
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Entry, className, funcName);
			}
			try
			{
				if (OracleTraceTag.Error == (tag & OracleTraceTag.Error) && level == OracleTraceLevel.Public)
				{
					flag = true;
				}
				else
				{
					switch (level)
					{
					case OracleTraceLevel.Config:
						flag = ProviderConfig.m_bTraceLevelConfig;
						break;
					case OracleTraceLevel.Network:
						flag = ProviderConfig.m_bTraceLevelNetwork;
						break;
					case OracleTraceLevel.Private:
						flag = ProviderConfig.m_bTraceLevelPrivate;
						break;
					case OracleTraceLevel.Public:
						flag = ProviderConfig.m_bTraceLevelPublic;
						break;
					}
				}
				if (ex is OracleException)
				{
					if (oracleLogicalTransaction != null && oracleLogicalTransaction.m_ltxId != null)
					{
						try
						{
							if (((OracleException)ex).IsRecoverable && (((OracleException)ex).m_OracleLogicalTransaction == null || ((OracleException)ex).m_OracleLogicalTransaction.m_ltxId == null) && oracleLogicalTransaction.m_connection != null && !oracleLogicalTransaction.m_connection.bConnectionforTxnStatus)
							{
								((OracleException)ex).m_OracleLogicalTransaction = oracleLogicalTransaction;
								OracleConnection oracleConnection = null;
								try
								{
									oracleConnection = ((OracleException)ex).m_OracleLogicalTransaction.m_connection;
									oracleConnection.bIgnoreLogicalTransaction = true;
									oracleConnection.Close();
								}
								catch
								{
								}
								finally
								{
									oracleConnection.bIgnoreLogicalTransaction = false;
								}
								if (((OracleException)ex).OracleLogicalTransaction.m_ltxId != null && ((OracleException)ex).OracleLogicalTransaction.bDistributed == false)
								{
									((OracleException)ex).m_OracleLogicalTransaction.GetOutcome();
								}
							}
						}
						finally
						{
							oracleLogicalTransaction.m_connection = null;
						}
					}
					if (((OracleException)ex).m_OracleLogicalTransaction == null)
					{
						((OracleException)ex).m_OracleLogicalTransaction = new OracleLogicalTransaction(null, null);
					}
				}
				if (!(ex is NetworkException))
				{
					return;
				}
				OracleException ex2 = new OracleException((NetworkException)ex);
				if (oracleLogicalTransaction != null && oracleLogicalTransaction.m_ltxId != null)
				{
					try
					{
						if (ex2.IsRecoverable && oracleLogicalTransaction.m_connection != null && !oracleLogicalTransaction.m_connection.bConnectionforTxnStatus)
						{
							ex2.m_OracleLogicalTransaction = oracleLogicalTransaction;
							OracleConnection oracleConnection2 = null;
							try
							{
								oracleConnection2 = ((OracleException)ex).m_OracleLogicalTransaction.m_connection;
								oracleConnection2.bIgnoreLogicalTransaction = true;
								oracleConnection2.Close();
							}
							catch
							{
							}
							finally
							{
								oracleConnection2.bIgnoreLogicalTransaction = false;
							}
							if (oracleLogicalTransaction.bDistributed == false)
							{
								ex2.m_OracleLogicalTransaction.GetOutcome();
							}
						}
					}
					finally
					{
						oracleLogicalTransaction.m_connection = null;
					}
				}
				if (ex2.m_OracleLogicalTransaction == null)
				{
					ex2.m_OracleLogicalTransaction = new OracleLogicalTransaction(null, null);
				}
				if (ex2.OracleLogicalTransaction == null || ex2.OracleLogicalTransaction.UserCallCompleted != true || ex2.OracleLogicalTransaction.Committed != true)
				{
					throw ex2;
				}
			}
			finally
			{
				try
				{
					if (flag)
					{
						Trace.Write(level, tag, className, funcName, Trace.GetCPInfo(null, null, null, null) + ex.ToString());
					}
				}
				catch
				{
				}
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.Exit, className, funcName);
				}
			}
		}
	}
}
